﻿using System.Net;

namespace Subtitles.OpenSubtitlesSubtitlesProvider
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.IO;

    using CookComputing.XmlRpc;

    using MEF_Test.Bricks.Subtitles;
    using MEF_Test.Contracts;
    using MEF_Test.Subtitles;

    using Mydra.IsdbTools;

    /// <summary>
    /// A subtitles provider fot Open Subtitles
    /// </summary>
    /// <remarks>See www.opensubtitles.org/isdb</remarks>
    [Export(typeof(ISubtitlesProvider))]
    public class OpenSubtitlesSubtitlesProvider : SubtitlesProviderBase
    {
        /// <summary>
        /// A string representing the language codes to search.
        /// </summary>
        private readonly string _languageCodesToSearch;

        /// <summary>
        /// Holds the name of the provider.
        /// </summary>
        private const string PROVIDER_LABEL = "Open Subtitles";

        /// <summary>
        /// Initializes a new instance of the <see cref="OpenSubtitlesSubtitlesProvider"/> class.
        /// </summary>
        /// <param name="settingsManager">The settings manager.</param>
        /// <param name="subtitleFormatHandlersProvider">The class providing handlers for the different subtitle formats</param>
        [ImportingConstructor]
        public OpenSubtitlesSubtitlesProvider(ISettingsManager settingsManager, ISubtitleFormatHandlersProvider subtitleFormatHandlersProvider) : base(subtitleFormatHandlersProvider)
        {
            _languageCodesToSearch = settingsManager.GetSetting<string>(SettingStringIdentifiers.LanguageCodesToSearch);            
            
            if (_languageCodesToSearch == null)
            {
                _languageCodesToSearch = string.Empty;
            }
        }    

        /// <summary>
        /// Gets the name of the provider.
        /// </summary>
        /// <returns>the name of the provider</returns>
        public override string GetProviderName()
        {
            return PROVIDER_LABEL;
        }

        /// <summary>
        /// Gets the subtitles.
        /// </summary>
        /// <param name="node">The media node.</param>
        /// <returns>The subtitles description</returns>
        public override IEnumerable<ISubtitleViewModel> GetSubtitles(IBrowserNodeViewModel node)
        {            
            return GetSubtitles(node.FileHandler.GetStream(), _languageCodesToSearch);         
        }

        /// <summary>
        /// Downloads the subtitle file.
        /// </summary>
        /// <param name="subtitleViewModel">The subtitle view model.</param>
        /// <returns>
        /// A stream to the content of the subtitle file.
        /// </returns>
        public override Stream OpenSubtitleFile(int subtitleViewModel)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Gets the subtitles.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="subLanguageId">The sub language id.</param>
        /// <returns>A list of matching subtitles.</returns>
        public IEnumerable<ISubtitleViewModel> GetSubtitles(Stream stream, string subLanguageId)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            if (subLanguageId == null)
            {
                throw new ArgumentNullException("subLanguageId");
            }

            var iosdb = XmlRpcProxyGen.Create<IOSDb>();
            
            // TODO : Catch subtitles-API-specific exceptions and rethrow mydra-wide subtitles exceptions.
            var subs = iosdb.Login(string.Empty, string.Empty, "en", "MPC");
            var token = (string)subs["token"];

            byte[] byteArrayHash = IsdbHashesHelper.ComputeMovieHash(stream);
            string hash = IsdbHashesHelper.ToHexadecimal(byteArrayHash);
            
            long size = stream.Length;
            var structure = BuildSearchQuery(subLanguageId, hash, (int)size, string.Empty);

            // warning : the params must be arrays !
            var v = iosdb.SearchSubtitles(token, new[] { structure });
            
            var subtitles = new List<ISubtitleViewModel>();

            if (v["data"].ToString() != bool.FalseString)
            {
                foreach (XmlRpcStruct subtitle in (object[])v["data"])
                {
                    // SafeGetSubtitleFormatHandler returns a dummy format handler if none is found.
                    var subtitleFormatHandler = SubtitleFormatHandlersProvider.SafeGetSubtitleFormatHandler((string)subtitle["SubFormat"]);
                    // TODO : Use factories in order to be able to inject the dependency to this ViewModel.
                    var subtitleViewModel = new OpenSubtitlesSubtitleViewModel(subtitle, subtitleFormatHandler);
                    subtitles.Add(subtitleViewModel);
                }
            }

            return subtitles;
        }

        /// <summary>
        /// Builds the search query.
        /// </summary>
        /// <param name="subLanguageId">The sub language id.</param>
        /// <param name="movieHash">The movie hash.</param>
        /// <param name="movieByteSize">Size of the movie byte.</param>
        /// <param name="imdbId">The imdb id.</param>
        /// <returns>The search query.</returns>
        private XmlRpcStruct BuildSearchQuery(string subLanguageId, string movieHash, int movieByteSize, string imdbId)
        {
            XmlRpcStruct structure = new XmlRpcStruct();
            structure.Add("sublanguageid", subLanguageId);
            structure.Add("moviehash", movieHash);
            structure.Add("moviebytesize", movieByteSize);
            structure.Add("imdbid", imdbId);
            return structure;

        }    
    }

    public class OpenSubtitlesSubtitleViewModel : SubtitleViewModelBase
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="OpenSubtitlesSubtitleViewModel"/> class.
        /// </summary>
        /// <param name="openSubtitleXmlRpcStructure">The open subtitle XML RPC structure.</param>
        /// <param name="subtitleFormatHandler">The class in charge of handling the format of the subtitle file.</param>
        public OpenSubtitlesSubtitleViewModel(XmlRpcStruct openSubtitleXmlRpcStructure, ISubtitleFormatHandler subtitleFormatHandler)
        {
            Name = (string)openSubtitleXmlRpcStructure["SubFileName"];
            Uri = new Uri((string)openSubtitleXmlRpcStructure["SubDownloadLink"], UriKind.Absolute);
        }

        /// <summary>
        /// Gets or sets the URI.
        /// </summary>
        /// <value>The URI.</value>
        protected Uri Uri { get; set; }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The subtitle filenname.</value>
        public string Name { get; set; }

        /// <summary>
        /// Gets the content of the actual subtitles file.
        /// </summary>
        /// <remarks>Don't forget to close and dispose the returned Stream.</remarks>
        /// <returns>the text-based content of the subtitles file.</returns>
        public override Stream GetSubtitleFile()
        {
            WebClient client = new WebClient();
            return client.OpenRead(this.Uri);
        }
    }
}
